package com.jiegui.framework.utils;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.jiegui.common.core.redis.RedisCache;
import com.jiegui.common.exception.user.RRException;
import com.jiegui.common.model.AccessToken;
import com.jiegui.common.model.MessageSendModel;
import com.jiegui.common.model.WxChartModel;
import com.jiegui.common.model.WxUserInfo;
import com.jiegui.common.utils.HttpClientUtils;
import com.jiegui.common.utils.StringUtils;
import com.jiegui.common.utils.VerifyCodeUtils;
import com.jiegui.common.utils.http.HttpUtils;
import com.jiegui.common.utils.spring.SpringUtils;
import com.jiegui.framework.oss.OSSFactory;
import com.jiegui.system.service.ISystemConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Slf4j
public class WechatUtils {



    /**
     * 获取access_token的接口地址（GET） 限200（次/天）
     */
    public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    /**
     * 微信 认证接口
     */
    public static final String AUTH_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect ";

    /**
     * 获取 用户openId
     */
    public final static String ACCESS_TOKEN_URL_OPENID = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APPSECRET&code=CODE&grant_type=authorization_code";

    /**
     * 获取用户信息
     */
    public final static String USER_INFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";

    /**
     * 消息接口
     */
    public final static String SEND_MESSAGE_API_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";

    /**
     * 微信获取图片接口
     */
    public final static String GET_MEDIA_URL = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESSTOKEN&media_id=MEDIAID";

    /**
     * 获取jsapi_ticket
     */
    public final static String GET_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESSTOKEN&type=jsapi";



    /**
     * 获取access_token
     *
     * @return
     */
    public static String getSysAccessToken(WxChartModel entity) {

        RedisCache redisUtils = SpringUtils.getBean(RedisCache.class);
        String accessToken = "";
        try {
            accessToken = redisUtils.getCacheObject(entity.getPublicAppId() + "Token");
            log.info("通过缓存获取token");
            if(StringUtils.isEmpty(accessToken)){
                throw new RRException("token超时");
            }
            return accessToken;
        } catch (Exception e) {
            log.error("缓存token失败,异常:{}", e);
            AccessToken token = getAccessToken(entity);
            accessToken = token.getAccess_token();
            redisUtils.deleteObject(entity.getPublicAppId());
            return accessToken;
        }
    }

    /**
     * 获取access_token
     *
     * @return
     */
    private static AccessToken getAccessToken(WxChartModel entity) {
        AccessToken accessToken = null;
        RedisCache redisUtils = SpringUtils.getBean(RedisCache.class);
        String requestUrl = ACCESS_TOKEN_URL.replace("APPID", entity.getPublicAppId())
                .replace("APPSECRET", entity.getPublicSecret());
        JSONObject jsonObject = HttpClientUtils.sendJsonReq(requestUrl);
        // 如果请求成功
        log.info("获取token为:" + jsonObject.toJSONString());
        if (null == jsonObject || 0 != jsonObject.getIntValue("errcode")) {
            log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInteger("errcode"), jsonObject.getString("errmsg"));
            return null;
        }
        accessToken = new AccessToken();
        accessToken.setAccess_token(jsonObject.getString("access_token"));
        accessToken.setExpires_in(jsonObject.getInteger("expires_in"));
        redisUtils.setCacheObject( entity.getPublicAppId()+"Token", accessToken.getAccess_token(), 7000, TimeUnit.SECONDS);
        redisUtils.deleteObject(entity.getPublicAppId());
        //redisUtils.setKEy( entity.getPublicAppId(), , 7000L);
        return accessToken;
    }

    /**
     * 获取access_token
     *
     * @return
     */
    public static String getTicket(WxChartModel entity) {
        RedisCache redisUtils = SpringUtils.getBean(RedisCache.class);
        //WxConfig wxConfig = SpringUtils.getBean(WxConfig.class);
        JSONObject json = new JSONObject();
        String ticket = redisUtils.getCacheObject(entity.getPublicAppId() + "Ticket");
        //如果redis里面存在该信息则直接返回
//        if(StringUtils.isNotBlank(ticket)){
//             return ticket;
//        }
        String requestUrl = GET_TICKET_URL.replace("ACCESSTOKEN", getAccessToken(entity).getAccess_token());
        json = HttpClientUtils.sendJsonReq(requestUrl);
        redisUtils.setCacheObject(entity.getPublicAppId() + "Ticket", json.getString("ticket"), 7000,TimeUnit.SECONDS);
        return json.getString("ticket");
    }

    /**
     * 获取用户 openId
     *
     * @param code
     * @return
     */
    public static String getOpenId(String code, WxChartModel entity) {
        // WxConfig wxConfig = SpringUtils.getBean(WxConfig.class);
        String requestUrl = ACCESS_TOKEN_URL_OPENID.replace("APPID", entity.getPublicAppId())
                .replace("APPSECRET", entity.getPublicSecret())
                .replace("CODE", code);
        log.info("获取用户 openId,请求url：[{}]", requestUrl);
        JSONObject jsonObject = HttpClientUtils.sendJsonReq(requestUrl);
        log.info("获取用户 openId,响应：[{}]", jsonObject.toJSONString());
        // 如果请求成功
        if (null == jsonObject || 0 != jsonObject.getIntValue("errcode")) {
            log.error("获取openId失败 errcode:{} errmsg:{}", jsonObject.getInteger("errcode"), jsonObject.getString("errmsg"));
            return null;
        }
        return jsonObject.getString("openid");
    }


    /**
     * 获取用户信息
     *
     * @param openId
     * @return
     */
    public static WxUserInfo getUserInfo(String openId, WxChartModel platform) {
        String accessToken = getSysAccessToken(platform);
        String url = String.format(USER_INFO_URL.replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId));
        log.info("微信获取用户信息url:[{}]", url);
        String r = HttpClientUtils.sendReq(url);
        log.info("微信获取用户信息返回:[{}]", r);
        WxUserInfo wxUserInfo =  JSONObject.parseObject(r,WxUserInfo.class);
        if(StringUtils.isEmpty(wxUserInfo.getOpenid())){
            String url1 = String.format(USER_INFO_URL.replace("ACCESS_TOKEN", getAccessToken(platform).getAccess_token())
                    .replace("OPENID", openId));
            log.info("微信获取用户信息url:[{}]", url1);
            String r1 = HttpClientUtils.sendReq(url1);
            log.info("微信获取用户信息返回:[{}]", r1);
          return  JSONObject.parseObject(r1, WxUserInfo.class);
        }
        return wxUserInfo;
    }

    /**
     * 获取用户信息
     *
     * @param code
     * @param platform
     * @return
     */
    public static WxUserInfo AppletsUserInfo(String code, WxChartModel platform) {
        //微信的接口
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + platform.getAppletsAppId() +
                "&secret=" + platform.getAppletsSecret() + "&js_code=" + code + "&grant_type=authorization_code";
        RestTemplate restTemplate = new RestTemplate();
        //进行网络请求,访问url接口
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
        //根据返回值进行后续操作
        if (responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK) {
            String sessionData = responseEntity.getBody();
            sessionData = sessionData.replace("session_key", "sessionKey");
            Gson gson = new Gson();
            //解析从微信服务器获得的openid和session_key;
            WxUserInfo info = gson.fromJson(sessionData, WxUserInfo.class);
            return info;
        }
        return null;
    }


    /**
     * 判断字符串是否可以转化为JSON数组
     *
     * @param content
     * @return
     */
    public static boolean isArrayList(String content) {
        if (StringUtils.isBlank(content)) {
            return false;
        }
        StringUtils.isEmpty(content);
        try {
            String[] strArr = content.split(",");
            if (strArr.length > 0) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

    public static String urlToOss(String imgUrl) throws Exception {
        HttpURLConnection httpuRLConnection = null;
        URL httpUrl = new URL(imgUrl);
        httpuRLConnection = (HttpURLConnection) httpUrl.openConnection();
        httpuRLConnection.setConnectTimeout(5000);
        httpuRLConnection.setDoOutput(true);
        httpuRLConnection.setRequestMethod("GET");
        String contentType = httpuRLConnection.getContentType();
        String suffix = "." + contentType.substring(contentType.lastIndexOf("/"));
        suffix = suffix.replace("/", "");
        String url = OSSFactory.build().upload(httpuRLConnection.getInputStream(), "wechat/" + System.currentTimeMillis() + VerifyCodeUtils.randomCode(5) + suffix);
        log.info("转存微信文件成功文件地址为：" + url);
        return url;
    }


    public static Map<String, String> sign(String url, WxChartModel entity) {
        //WxConfig wxConfig = SpringUtils.getBean(WxConfig.class);
        String jsapi_ticket = getTicket(entity);
        Map<String, String> ret = new HashMap<String, String>();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";
        try {
            url = URLDecoder.decode(url, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        //注意这里参数名必须全部小写，且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + nonce_str +
                "&timestamp=" + timestamp +
                "&url=" + url;
        try {

//            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
//            crypt.reset();
//            crypt.update(string1.getBytes("UTF-8"));
//            byteToHex(crypt.digest());
            signature = SHA1(string1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // ret.put("url", url);

        ret.put("appId", entity.getPublicAppId());
        ret.put("timestamp", timestamp);
        ret.put("nonceStr", nonce_str);
        ret.put("signature", signature);
        return ret;
    }


    public static String SHA1(String str) {
        try {
            MessageDigest digest = MessageDigest
                    .getInstance("SHA-1"); //如果是SHA加密只需要将"SHA-1"改成"SHA"即可
            digest.update(str.getBytes());
            byte messageDigest[] = digest.digest();
            // Create Hex String
            StringBuffer hexStr = new StringBuffer();
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexStr.append(0);
                }
                hexStr.append(shaHex);
            }
            return hexStr.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }


    /**
     * 调用发送模板消息接口
     * @param tmessageSendVO
     * @param tmessageSendVO
     * @return
     */
    public static JSONObject SendTemplateMsg(MessageSendModel tmessageSendVO) {
        JSONObject result = null;
        if(StringUtils.isEmpty(tmessageSendVO.getTouser())) {
            log.info("发送模板消息---接收者openid为空");
            return result;
        }
        if(StringUtils.isEmpty(tmessageSendVO.getTemplateId())) {
            log.info("发送模板消息---模板ID为空");
            return result;
        }
        if(StringUtils.isEmpty(tmessageSendVO.getJwid())) {
            log.info("发送模板消息---JWID为空");
            return result;
        }
        if(StringUtils.isEmpty(tmessageSendVO.getData())) {
            log.info("发送模板消息---模板数据为空");
            return result;
        }
        Map<String,Object> param = new HashMap<String,Object>();
        //接收者openid
        param.put("touser", tmessageSendVO.getTouser());
        //模板ID
        param.put("template_id", tmessageSendVO.getTemplateId());
        //模板数据
        JSONObject dataJson = JSONObject.parseObject(tmessageSendVO.getData());
        param.put("data",(Map) dataJson);
        //模板跳转链接
        if(StringUtils.isNotEmpty(tmessageSendVO.getUrl())) {
            param.put("url", tmessageSendVO.getUrl());
        }
        //跳小程序所需数据
        if(StringUtils.isNotEmpty(tmessageSendVO.getMiniProgram())) {
            param.put("miniprogram", tmessageSendVO.getMiniProgram());
        }
        //所需跳转到的小程序appid
        if(StringUtils.isNotEmpty(tmessageSendVO.getAppId())) {
            param.put("appid", tmessageSendVO.getAppId());
        }
        //所需跳转到小程序的具体页面路径
        if(StringUtils.isNotEmpty(tmessageSendVO.getPagePath())) {
            param.put("pagepath", tmessageSendVO.getPagePath());
        }
        ISystemConfigService systemConfigService = SpringUtils.getBean(ISystemConfigService.class);
        WxChartModel wxChartModel = systemConfigService.queryWxChart("WeChart");
        String accessToken =getSysAccessToken(wxChartModel);
        if (accessToken != null) {
            String requestUrl = SEND_MESSAGE_API_URL;
            requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken);
            String data = JSONObject.toJSONString(param);
            log.info("发送模板消息方法执行前json参数 :{obj :" + data + "}");
            result= HttpClientUtils.sendJsonReq(requestUrl, data, "POST");
            log.info("发送模板消息方法执行后json参数 :{result :" + result.toString() + "}");
        }
        return result;
    }
    private static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
}
